##################################################################
# File : /lua/maui/scrolledcontrollist.lua
# Description : Scrolled Control List control
# Author : GPG
##################################################################

local Control = import('control.lua').Control
local Group = import('group.lua').Group
local LayoutHelpers = import('layouthelpers.lua')
local Scrollbar = import('/lua/maui/scrollbar.lua').Scrollbar
local UIUtil = import('/lua/ui/uiutil.lua')
local LazyVar = import('/lua/lazyvar.lua')

ScrolledControlList = Class(Group) {

    __init = function(self, parent, itemWidth, itemHeight, offset, topoffset, name)
        Group.__init(self, parent, name or "Scrolled Control List")
        self._itemWidth = itemWidth
        self._itemHeight = itemHeight
        self._name = name
        self._offset = offset
        self._topoffset = topoffset
        self._items = {}
        self._lines = 0
        self._top = {}
        self._top["Vert"] = 1
        self._visible = {}
        self._visible["Vert"] = LazyVar.Create()
        self._visible["Vert"]:Set(function() return math.floor(self.Height() / itemHeight) end)
        self:SetNeedsFrameUpdate(true)
        
        # Give it a scrollbar
        UIUtil.CreateVertScrollbarFor(self)
        
        self.HandleEvent = function(control, event)
            if event.Type == 'WheelRotation' then
                local lines = 1
                if event.WheelRotation > 0 then
                    lines = -1
                end
                control:ScrollLines("Vert", lines)
            end
        end
        
        self:ScrollSetTop("Vert", 1)
        self._CalcVisible()
    end,
    
    OnInit = function(self)
        Control.OnInit(self)
    end,
    
    OnFrame = function(self, elapsedTime)
        # HACK HACK HACK - calcvisible isn't being hit properly when the menu is created
        if not self:IsHidden() then
            self:_CalcVisible()  
        end  
    end,

    AddItems = function(self, controllist)
        local lastctrl = nil
        self._items = table.copy(controllist)

        for index, control in ipairs(self._items) do
            if not lastctrl then
                LayoutHelpers.AtLeftTopIn(control, self)
                #control.Left:Set(function() return self.Left() end)
                #control.Top:Set(function() return self.Top() + self._topoffset end)
            else
                LayoutHelpers.Below(control, lastctrl, self._offset)
                LayoutHelpers.AtLeftIn(control, self)
            end
            lastctrl = control    
            self._lines = self._lines + 1              
        end
        self:_CalcVisible()    
    end,
    
    GetItem = function(self, itemindex)
        local item = self._items[itemindex]
        return item
    end,
    
    DestroyAllItems = function(self)
        for index, control in ipairs(self._items) do
            control:Destroy() 
        end
    end,
    
    ######################################################-
    # Scrolling functions
    ######################################################-
    ScrollSetTop = function(self, axis, top)
        #LOG("*UITest: ", top)
        top = math.floor(top) 
        if top == self._top[axis] then return end
        self._top[axis] = math.max(math.min(self._lines - self._visible[axis]() + 1, top), 1)

        self:_CalcVisible()
    end,
    
    ScrollLines = function(self, axis, delta)
        self:ScrollSetTop(axis, self._top[axis] + delta)
    end,

    ScrollPages = function(self, axis, delta)
        self:ScrollSetTop(axis, self._top[axis] + (delta * self._visible[axis]()))
    end,
    
    GetScrollValues = function(self, axis)
        local rangeMin = 0
        local rangeMax = math.max(self._lines, self._visible[axis]())
        local visibleMin = self._top[axis] - 1
        local visibleMax = (self._top[axis] - 1) + self._visible[axis]()

        return rangeMin, rangeMax, visibleMin, visibleMax
    end,
    
    IsScrollable = function(self, axis)
        if self._lines > self._visible[axis]() then
            return true
        else
            return false
        end
    end,
    
    _CalcVisible = function(self)
        if not self._lines then return end # protect against premature calls
        
        for line = 1, self._lines do
            local ctrl = self._items[line]
            if ctrl then
                if (line >= self._top["Vert"]) and (line < self._top["Vert"] + self._visible["Vert"]()) then
                    if not self:IsHidden() then
                        ctrl:SetHidden(false)
                    end
                    ctrl.Top:Set(function() return math.floor(((line - self._top["Vert"]) * self._itemHeight) + self.Top()) end)
                    # The top won't set if I don't actually call it again, I don't know why
                    ctrl.Top()
                    #LOG("*UITest: ", ctrl.Top())
                else
                    ctrl:SetHidden(true)
                end
            end
        end
    end,
    
    OnHide = function(self, hidden)
        if self:IsHidden() != hidden then
            self:_CalcVisible()
        end
    end,
           
}

